/**
 *  @(#)  IFAAAuthenticator  module    1.0  2017/03/24
 *
 *  Copyright  (c)  2017,  IFAA  and/or  its  affiliates.  All  rights  reserved.
 *
 *  Redistribution  and  use  in  source  and  binary  forms,  with  or  without
 *  modification,  are  permitted  provided  that  the  following  conditions  are  met:
 *
 *  -Redistribution  of  source  code  must  retain  the  above  copyright  notice,  this
 *    list  of  conditions  and  the  following  disclaimer.
 *
 *  -Redistribution  in  binary  form  must  reproduce  the  above  copyright  notice,
 *    this  list  of  conditions  and  the  following  disclaimer  in  the  documentation
 *    and/or  other  materials  provided  with  the  distribution.
 *
 *  Neither  the  name  of  IFAA  or  the  names  of  contributors  may
 *  be  used  to  endorse  or  promote  products  derived  from  this  software  without
 *  specific  prior  written  permission.
 *
 *  This  software  is  provided  "AS  IS,"  without  a  warranty  of  any  kind.  ALL
 *  EXPRESS  OR  IMPLIED  CONDITIONS,  REPRESENTATIONS  AND  WARRANTIES,  INCLUDING
 *  ANY  IMPLIED  WARRANTY  OF  MERCHANTABILITY,  FITNESS  FOR  A  PARTICULAR  PURPOSE
 *  OR  NON-INFRINGEMENT,  ARE  HEREBY  EXCLUDED.  IFAA,  ORG.
 *  AND  ITS  LICENSORS  SHALL  NOT  BE  LIABLE  FOR  ANY  DAMAGES  SUFFERED  BY  LICENSEE
 *  AS  A  RESULT  OF  USING,  MODIFYING  OR  DISTRIBUTING  THIS  SOFTWARE  OR  ITS
 *  DERIVATIVES.  IN  NO  EVENT  WILL  IFAA  OR  ITS  LICENSORS  BE  LIABLE  FOR  ANY  LOST
 *  REVENUE,  PROFIT  OR  DATA,  OR  FOR  DIRECT,  INDIRECT,  SPECIAL,  CONSEQUENTIAL,
 *  INCIDENTAL  OR  PUNITIVE  DAMAGES,  HOWEVER  CAUSED  AND  REGARDLESS  OF  THE  THEORY
 *  OF  LIABILITY,  ARISING  OUT  OF  THE  USE  OF  OR  INABILITY  TO  USE  THIS  SOFTWARE,
 *  EVEN  IF  IFAA  HAS  BEEN  ADVISED  OF  THE  POSSIBILITY  OF  SUCH  DAMAGES.
 *
 *  You  acknowledge  that  this  software  is  not  designed,  licensed  or  intended
 *  for  use  in  the  design,  construction,  operation  or  maintenance  of  any
 *  nuclear  facility.
 *
 */
package com.ifaa.sdk.util;

import java.math.BigInteger;

/**
 * 
 * @author junsui.ljs
 * @version $Id: ByteUtils.java, v 0.1
 */
public class ByteUtils {
    
    /**
     * hex String
     */
    public final static String HEX_DIGITS = "0123456789ABCDEF";
    
    /**
     * hex char array
     */
    final protected static char[] HEX_ARRAY = HEX_DIGITS.toCharArray();

    /**
     * convert bytes to hex string
     * 
     * @param bytes
     * @return
     */
    public static String toHexString(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }
    
    /**
     * convert bytes to hex string
     * 
     * @param bytes
     * @return
     */
    public static byte[] hexToBytes(String hexString) {
        
        if ((hexString.length() &1) != 0) {
            hexString = "0" + hexString;
        }
        
        hexString = hexString.toUpperCase();  
        
        int length = hexString.length() / 2;  
        
        char[] hexChars = hexString.toCharArray(); 
        
        byte[] result = new byte[length];  
        
        for (int i = 0; i < length; i++) {  
            int pos = i * 2;  
            result[i] = (byte) (hexChartoByte(hexChars[pos]) << 4 | hexChartoByte(hexChars[pos + 1]));  
              
        }  
        return result; 
    }
    
    /**
     * Convert hex char to byte;
     * 
     * @param c
     * @return
     */
    private static byte hexChartoByte(char c) {  
        return (byte) HEX_DIGITS.indexOf(c);  
    }


    /**
     * change from byte[] to int
     * 
     * @param input input byte[]
     * @return int value of input
     */
    public static int toInt(byte[] input) {
        return toInt(input, 0);
    }

    /**
     * change from byte[] to int
     * 
     * @param input input byte[]
     * @param offset begin offset of the input byte[]
     * @return int value of input
     */
    public static int toInt(byte[] input, int offset) {
        int result = (input[offset + 3] & 0xff) << 24;
        result += (input[offset + 2] & 0xff) << 16;
        result += (input[offset + 1] & 0xff) << 8;
        result += (input[offset + 0] & 0xff);
        return result;
    }
    
    /**
     * change from byte[] to int
     * 
     * @param input input byte[]
     * @return int value of input
     */
    public static int toUInt16(byte[] input) {
        return toUInt16(input, 0);
    }
    
    /**
     * change from byte[] to int
     * 
     * @param input input byte[]
     * @param offset begin offset of the input byte[]
     * @return int value of input
     */
    public static int toUInt16(byte[] input, int offset) {
        int result = (input[offset + 1] & 0xff) << 8;
        result += (input[offset + 0] & 0xff);
        return result;
    }
    
    /**
     * write a int to dest byte[]
     * 
     * @param input int to be written
     * @param dest  dest byte[] to be written 
     * @param offset dest byte[] begin offset to be written 
     */
    public static void writeUInt16(int input, byte[] dest, int offset) {
        dest[offset + 0] = (byte) (input & 0xff);
        dest[offset + 1] = (byte) ((input >> 8) & 0xff);
    }

    /**
     * write a int to dest byte[]
     * 
     * @param input int to be written
     * @param dest  dest byte[] to be written 
     * @param offset dest byte[] begin offset to be written 
     */
    public static void write(int input, byte[] dest, int offset) {
        dest[offset + 0] = (byte) (input & 0xff);
        dest[offset + 1] = (byte) ((input >> 8) & 0xff);
        dest[offset + 2] = (byte) ((input >> 16) & 0xff);
        dest[offset + 3] = (byte) ((input >> 24) & 0xff);
    }

    /**
     * write a byte[] to dest byte[]
     * 
     * @param input int to be written
     * @param dest  dest byte[] to be written 
     * @param offset dest byte[] begin offset to be written 
     */
    public static void write(byte[] input, int length, byte[] dest, int offset) {
        for (int i = 0; i < length; i++) {
            dest[offset + i] = input[i];
        }
    }

    /**
     * copy from input byte[] into dest byte[]
     * 
     * @param input
     * @param inputOffset
     * @param length
     * @param dest
     * @param destOffset
     */
    public static void copy(byte[] input, int inputOffset, int length, byte[] dest, int destOffset) {
        for (int i = 0; i < length; i++) {
            dest[destOffset + i] = input[inputOffset + i];
        }
    }

    /**
     * convert int into byte[]
     * 
     * @param idx
     * @return
     */
    public static byte[] toBytes(int idx) {
        byte[] result = new byte[4];
        write(idx, result, 0);
        return result;
    }
    
    /**
     * convert a byte[] to BigInteger
     * 
     * @param data input data
     * @param offset start offset
     * @param length length need to convert
     * @return BigInteger
     */
    public static BigInteger toBigInteger(byte[] data, int offset, int length) {
        
        byte[] bigIntegerData =  new byte[length]; 
        
        write(data, length, bigIntegerData, offset);
        
        return new BigInteger(bigIntegerData);
    }
    
    /**
     * convert a byte[] to BigInteger
     * 
     * @param data input data
     * @return BigInteger
     */
    public static BigInteger toBigInteger(byte[] data) {
        return new BigInteger(data);
    }

}
